/* 
 * File:   EXEC.cpp
 * Author: Saulo
 * 
 * Created on 23 de Maio de 2010, 22:10
 */

#include "EXEC.h"
#include "IF.h"

EXEC::EXEC(registradores* _regs, IF* _iF) {
    this->Initialize();
    this->op = new operacoes();
    this->regs = _regs;
    this->iF = _iF;

}

void EXEC::Initialize() {
    s_mapStringInstructions["add"] = add; //1
    s_mapStringInstructions["addinc"] = addinc; //2
    s_mapStringInstructions["iand"] = iand; //3
    s_mapStringInstructions["andnota"] = andnota; //4


    s_mapStringInstructions["deca"] = deca; //7
    s_mapStringInstructions["inca"] = inca; //8
    s_mapStringInstructions["j"] = j; //9
    s_mapStringInstructions["lsl"] = lsl;
    s_mapStringInstructions["lsr"] = lsr;
    s_mapStringInstructions["nand"] = nand;
    s_mapStringInstructions["nor"] = nor;
    s_mapStringInstructions["ones"] = ones;
    s_mapStringInstructions["ior"] = ior;
    s_mapStringInstructions["ornotb"] = ornotb;
    s_mapStringInstructions["passa"] = passa;
    s_mapStringInstructions["passnota"] = passnota;
    s_mapStringInstructions["sub"] = sub;
    s_mapStringInstructions["subdec"] = subdec;
    s_mapStringInstructions["ixnor"] = ixnor;
    s_mapStringInstructions["ixor"] = ixor;
    s_mapStringInstructions["zeros"] = zeros;
    s_mapStringInstructions["addi"] = addi;

    s_mapStringRegs["rt0"] = rt0;
    s_mapStringRegs["rt1"] = rt1;
    s_mapStringRegs["rt2"] = rt2;
    s_mapStringRegs["rt3"] = rt3;
    s_mapStringRegs["rt4"] = rt4;
    s_mapStringRegs["rt5"] = rt5;
    s_mapStringRegs["rt6"] = rt6;
    s_mapStringRegs["rt7"] = rt7;
}

reg EXEC::escolhe(string id) {

    switch (s_mapStringRegs[id]) {
        case rt0:
            return regs->GetR0();
            break;
        case rt1:
            return regs->GetR1();
            break;
        case rt2:
            return regs->GetR2();
            break;
        case rt3:
            return regs->GetR3();
            break;
        case rt4:
            return regs->GetR4();
            break;
        case rt5:
            return regs->GetR5();
            break;
        case rt6:
            return regs->GetR6();
            break;
        case rt7:
            return regs->GetR7();
            break;

    }

}

void EXEC::setBuffer(reg _tmp, string _id) {

    this->buffer.id = _id;
    this->buffer.r = _tmp;
            this->buffer.acao = true;

}

void EXEC::setBuffer() {

    this->buffer.acao = false;

}

EXEC::EXEC(const EXEC& orig) {
}

EXEC::~EXEC() {
}

bufferEXEC EXEC::getBuffer(){
    return buffer;
}

void EXEC::executa(vector<string> instrucoes) {

    string instrucao = instrucoes.at(0);

    reg a, b, c;

    switch (s_mapStringInstructions[instrucao]) {

        case add://1
            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_add(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case addinc://2
            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_addinc(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case iand://3
            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_and(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case andnota://4

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_andnota(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case deca://7

            a = escolhe(instrucoes.at(2));
            c = op->i_deca(a);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case inca://8

            a = escolhe(instrucoes.at(2));
            c = op->i_inca(a);
            this->setBuffer(c, instrucoes.at(1));
            break;

        case j://9
            this->iF->setPC(atoi(instrucoes.at(1).c_str()));
            this->setBuffer();
            break;


        case lsl:

            a = escolhe(instrucoes.at(2));
            c = op->i_lsl(a);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case lsr:

            a = escolhe(instrucoes.at(2));
            c = op->i_lsr(a);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case nand:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_nand(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case nor:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_nor(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case ones:

            c = op->i_ones();
            this->setBuffer(c, instrucoes.at(1));
            break;


        case ior:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_or(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case ornotb:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_ornotb(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case passa:

            a = escolhe(instrucoes.at(2));
            c = op->i_passa(a);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case passnota:

            a = escolhe(instrucoes.at(2));
            c = op->i_passnota(a);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case sub:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_sub(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case subdec:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_subdec(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case ixnor:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_xnor(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case ixor:

            a = escolhe(instrucoes.at(2));
            b = escolhe(instrucoes.at(3));
            c = op->i_xor(a, b);
            this->setBuffer(c, instrucoes.at(1));
            break;


        case zeros:
            c = op->i_zeros();
            this->setBuffer(c, instrucoes.at(1));
            break;

        case addi:
            a = escolhe(instrucoes.at(2));
            int i = atoi(instrucoes.at(3).c_str());
            c = op->i_addi(a, i);
            this->setBuffer(c, instrucoes.at(1));
            break;

    }

}
